﻿// Decompiled with JetBrains decompiler
// Type: Netick.SimulationClock
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;

#nullable disable
namespace Netick;

public sealed class SimulationClock
{
  internal NetickEngine Engine;
  internal double Time;
  internal bool HeavyPktLoss;
  internal bool IsLastCall = true;
  internal bool IsFirstCall = true;
  internal float RawDeltaTime;
  internal float _deltaTime;
  private float _prevDeltaTimeForAdjust;
  private double _accumulator;
  private double _lastAdjust;
  private double _packetTime;
  private float _scaledFixedDelta;
  private float _realScaledFixedDelta;

  public float Alpha { get; private set; }

  internal double Accumulator => this._accumulator;

  public float FixedDelta { get; private set; }

  public float DeltaTime => this._deltaTime;

  internal SimulationClock(NetickEngine engine)
  {
    this.Engine = engine;
    this.FixedDelta = 1f / engine.Config.TickRate;
    this._scaledFixedDelta = this.FixedDelta;
    this._realScaledFixedDelta = this._scaledFixedDelta;
    if ((double) this.Engine._config.MaxAllowedTimestep > (double) this.FixedDelta)
      return;
    NetickLogger.LogError(engine, (object) $"{"MaxAllowedTimestep"} (equal to {this.Engine._config.MaxAllowedTimestep}) is lower than 1.0/tickrate (equal to {this.FixedDelta}). {"MaxAllowedTimestep"} must be several times the value of 1.0/tickrate, please increase it Netick Settings.");
  }

  internal void Start()
  {
    this._scaledFixedDelta = this.FixedDelta;
    this._accumulator = 0.0;
    this.Alpha = 0.0f;
  }

  internal void Set(float time) => this._accumulator = (double) time;

  internal void Reset()
  {
    this.HeavyPktLoss = false;
    this._packetTime = this.Time;
    this.Set(this.FixedDelta * 2f);
    if (!this.Engine.IsClient)
      return;
    this.Set(this.FixedDelta * 4f);
  }

  internal void OnServerPacket()
  {
    this._packetTime = this.Time;
    this.HeavyPktLoss = false;
  }

  internal void OnHeavyLoss()
  {
    this._scaledFixedDelta = this.FixedDelta;
    this._accumulator = (double) this.FixedDelta;
    this._lastAdjust = this.Time;
    this._packetTime = this.Time;
    this.HeavyPktLoss = true;
  }

  internal void AdjustClock(
    double latency,
    double receiveDeltaAvg,
    double receiveDeltaStd,
    double currentTick,
    double remoteTick,
    int serverDivisor)
  {
    float deltaTimeForAdjust = this._prevDeltaTimeForAdjust;
    this._prevDeltaTimeForAdjust = this._deltaTime;
    if ((double) this._deltaTime - (double) deltaTimeForAdjust > 0.0099999997764825821 || this._packetTime == 0.0)
      return;
    double num1 = this.Time - this._packetTime;
    double val2 = (double) serverDivisor * (double) this.FixedDelta;
    double num2 = (double) this.FixedDelta * 0.4;
    latency = Math.Max(latency, val2);
    double num3 = Math.Min(latency, 2.0) - (double) this.FixedDelta * 0.3;
    double num4 = Math.Max(0.0, (Math.Max(0.0, (receiveDeltaAvg - val2) * 3.0) + Math.Max(0.0, receiveDeltaStd * 3.5)) / (double) this.FixedDelta);
    double num5 = (double) (serverDivisor - 1) + num4;
    double val1 = (remoteTick + (num1 + num3) / (double) this.FixedDelta + num5 - currentTick) * (double) this.FixedDelta;
    if (val1 > num2)
    {
      if (this.Time - this._lastAdjust > 0.699999988079071 && val1 > (double) this.FixedDelta * 3.0 && this._accumulator < (double) this.FixedDelta * 3.0)
      {
        this._accumulator += Math.Min(val1, 5.0 * (double) this.FixedDelta);
        this._lastAdjust = this.Time;
      }
      if (val1 > (double) this.FixedDelta * 10.0)
        this._scaledFixedDelta = 0.2f * this.FixedDelta;
      else if (val1 > (double) this.FixedDelta * 5.0)
        this._scaledFixedDelta = 0.3f * this.FixedDelta;
      else if (val1 > (double) this.FixedDelta * 2.0)
        this._scaledFixedDelta = 0.7f * this.FixedDelta;
      else if (val1 > (double) this.FixedDelta * 1.0)
        this._scaledFixedDelta = 0.97f * this.FixedDelta;
      else
        this._scaledFixedDelta = 0.99f * this.FixedDelta;
    }
    else if (val1 < -num2)
    {
      if (val1 < -(double) this.FixedDelta * 10.0)
        this._scaledFixedDelta = 1.2f * this.FixedDelta;
      else if (val1 < -(double) this.FixedDelta * 4.0)
        this._scaledFixedDelta = 1.06f * this.FixedDelta;
      else if (val1 < -(double) this.FixedDelta * 2.0)
        this._scaledFixedDelta = 1.03f * this.FixedDelta;
      else
        this._scaledFixedDelta = 1.01f * this.FixedDelta;
    }
    else
      this._scaledFixedDelta = this.FixedDelta;
  }

  internal void PreUpdate(float deltaTime, float timeScale)
  {
    this.IsLastCall = false;
    this.IsFirstCall = true;
    this.RawDeltaTime = deltaTime / timeScale;
    this._deltaTime = this.RawDeltaTime;
    this._accumulator += (double) this._deltaTime;
    this.Time += (double) this._deltaTime;
    this.Alpha = NetickUtils.Clamp01((float) this._accumulator / this._realScaledFixedDelta);
    if (!this.Engine._lastFrameATickWasExecuted)
      return;
    if (this.Engine.IsServer)
      this.Engine._profiler.ServerTickTime?.Update(this.RawDeltaTime);
    this.Engine._lastFrameATickWasExecuted = false;
  }

  internal void Update(int serverDivisor)
  {
    int num1 = 0;
    int num2 = Math.Max(1, (int) ((double) this.Engine._config.MaxAllowedTimestep / (double) this.FixedDelta));
    while (num1 < num2 && this._accumulator >= (double) this._realScaledFixedDelta)
    {
      this._realScaledFixedDelta = this._scaledFixedDelta;
      this._accumulator -= (double) this._realScaledFixedDelta;
      this.Alpha = NetickUtils.Clamp01((float) this._accumulator / this._realScaledFixedDelta);
      this.IsFirstCall = num1 == 0;
      this.IsLastCall = this._accumulator < (double) this._realScaledFixedDelta;
      ++num1;
      if (num1 == num2)
        this.IsLastCall = true;
      this.Engine.Step();
    }
    this.Alpha = NetickUtils.Clamp01((float) this._accumulator / this._realScaledFixedDelta);
    if (!this.Engine.IsClient || !this.Engine._client.IsConnected || !this.Engine._cliSim.CurrentTick.IsValid || !this.Engine._cliSim.AuthoritativeTick.IsValid)
      return;
    if (!this.HeavyPktLoss)
      this.AdjustClock(this.Engine._client.ConnectedServer.RTT.Average, this.Engine._cliSim.InputReceiveDeltaAvg, this.Engine._cliSim.InputReceiveDeltaStd, (double) this.Engine._cliSim.CurrentTick.Value, (double) this.Engine._cliSim.AuthoritativeTick.Value, serverDivisor);
    else
      this._scaledFixedDelta = this.FixedDelta;
  }
}
